using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;

namespace EntityKit.Runtime
{
    /// <summary>
    /// 配置表管理器
    /// 用于注册、管理和获取配置表数据
    /// </summary>
    public static class ConfigTableKit
    {
        /// <summary>
        /// 存储所有配置表的字典
        /// Key: 配置表标识符
        /// Value: 配置表数据字典（ID -> ConfigTableBase）
        /// </summary>
        private static readonly Dictionary<string, Dictionary<int, ConfigTableBase>> mConfigTables = new();

        /// <summary>
        /// 注册配置表（泛型版本）
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="textAsset">包含JSON数据的TextAsset</param>
        public static void RegisterConfigTable<T>(string key, TextAsset textAsset) where T : ConfigTableBase
        {
            // 参数验证
            if (string.IsNullOrEmpty(key))
            {
                Debug.LogError("配置表标识符不能为空");
                return;
            }

            if (textAsset == null)
            {
                Debug.LogError("TextAsset不能为空");
                return;
            }

            // 检查是否已存在相同标识符的配置表
            if (mConfigTables.ContainsKey(key))
            {
                Debug.LogError($"已存在相同标识符的配置表: {key}");
                return;
            }

            // 解析JSON数据
            List<T> sourceData = null;
            try 
            {
                sourceData = JsonMapper.ToObject<List<T>>(textAsset.text);
            }
            catch (Exception ex)
            {
                Debug.LogError($"序列化类型错误 key {key} Type {typeof(T).Name} Exception: {ex.Message}");
                return;
            }
            
            if (sourceData == null)
            {
                Debug.LogError($"序列化类型错误 key {key} Type {typeof(T).Name}");
                return;
            }

            // 构建配置表字典
            var dic = new Dictionary<int, ConfigTableBase>(sourceData.Count);
            foreach (var config in sourceData)
            {
                if (config == null)
                {
                    Debug.LogError($"配置表 {key} 中存在空数据");
                    continue;
                }

                if (!dic.TryAdd(config.ID, config))
                {
                    Debug.LogError($"{typeof(T)} 中存在相同ID:{config.ID}");
                    return;
                }
            }

            mConfigTables[key] = dic;
        }

        /// <summary>
        /// 注销配置表
        /// </summary>
        /// <param name="key">配置表标识符</param>
        /// <returns>是否成功注销</returns>
        public static bool UnRegisterConfigTable(string key)
        {
            if (string.IsNullOrEmpty(key))
                return false;

            return mConfigTables.Remove(key);
        }

        /// <summary>
        /// 清空所有配置表
        /// </summary>
        public static void Release()
        {
            mConfigTables.Clear();
        }

        /// <summary>
        /// 获取单行配置数据
        /// </summary>
        /// <param name="key">配置表标识符</param>
        /// <param name="id">配置项ID</param>
        /// <param name="isCopy">是否返回副本（true为返回副本，false为返回源数据）</param>
        /// <returns>配置项数据</returns>
        public static ConfigTableBase GetSingleRowConfig(string key, int id, bool isCopy = false)
        {
            if (string.IsNullOrEmpty(key))
                return null;

            if (!mConfigTables.TryGetValue(key, out var dict))
                return null;

            if (dict.TryGetValue(id, out var config))
            {
                if (isCopy && config != null)
                    return config.Clone();
                
                return config;
            }
            
            return null;
        }

        /// <summary>
        /// 获取单行配置数据（泛型版本）
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="id">配置项ID</param>
        /// <param name="isCopy">是否返回副本（true为返回副本，false为返回源数据）</param>
        /// <returns>配置项数据</returns>
        public static T GetSingleRowConfig<T>(string key, int id, bool isCopy = false) where T : ConfigTableBase
        {
            var singleRowConfig = GetSingleRowConfig(key, id, isCopy);
            return singleRowConfig as T;
        }

        /// <summary>
        /// 获取配置表字典
        /// </summary>
        /// <param name="key">配置表标识符</param>
        /// <param name="isCopy">是否返回副本（true为返回副本，false为返回源数据）</param>
        /// <returns>配置表字典</returns>
        public static Dictionary<int, ConfigTableBase> GetConfigTableDic(string key, bool isCopy = false)
        {
            if (string.IsNullOrEmpty(key))
                return null;

            if (!mConfigTables.TryGetValue(key, out var dict))
                return null;

            if (isCopy)
            {
                // 返回字典的副本，避免用户修改原始数据
                var clonedDict = new Dictionary<int, ConfigTableBase>(dict.Count);
                foreach (var kvp in dict)
                {
                    clonedDict[kvp.Key] = kvp.Value?.Clone();
                }
                return clonedDict;
            }
            
            return new Dictionary<int, ConfigTableBase>(dict);
        }

        /// <summary>
        /// 获取配置表字典（泛型版本）
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="isCopy">是否返回副本（true为返回副本，false为返回源数据）</param>
        /// <returns>配置表字典</returns>
        public static Dictionary<int, T> GetConfigTableDic<T>(string key, bool isCopy = false) where T : ConfigTableBase
        {
            if (string.IsNullOrEmpty(key))
                return null;

            if (!mConfigTables.TryGetValue(key, out var dict))
                return null;

            if (isCopy)
            {
                var result = new Dictionary<int, T>(dict.Count);
                foreach (var kvp in dict)
                {
                    if (kvp.Value is T typedValue)
                        result[kvp.Key] = typedValue.Clone() as T;
                }
                return result;
            }
            
            var directResult = new Dictionary<int, T>(dict.Count);
            foreach (var kvp in dict)
            {
                if (kvp.Value is T typedValue)
                    directResult[kvp.Key] = typedValue;
            }
            return directResult;
        }

        /// <summary>
        /// 获取配置表列表
        /// </summary>
        /// <param name="key">配置表标识符</param>
        /// <param name="isCopy">是否返回副本（true为返回副本，false为返回源数据）</param>
        /// <returns>配置表列表</returns>
        public static List<ConfigTableBase> GetConfigTableList(string key, bool isCopy = false)
        {
            if (string.IsNullOrEmpty(key))
                return new List<ConfigTableBase>();

            var dict = GetConfigTableDic(key, isCopy);
            return dict?.Values.ToList() ?? new List<ConfigTableBase>();
        }

        /// <summary>
        /// 获取配置表列表（泛型版本）
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="isCopy">是否返回副本（true为返回副本，false为返回源数据）</param>
        /// <returns>配置表列表</returns>
        public static List<T> GetConfigTableList<T>(string key, bool isCopy = false) where T : ConfigTableBase
        {
            if (string.IsNullOrEmpty(key))
                return new List<T>();

            var dict = GetConfigTableDic<T>(key, isCopy);
            return dict?.Values.ToList() ?? new List<T>();
        }

        /// <summary>
        /// 获取配置表数据行数
        /// </summary>
        /// <param name="key">配置表标识符</param>
        /// <returns>配置表数据行数</returns>
        public static int GetConfigsDataRowCount(string key)
        {
            if (string.IsNullOrEmpty(key))
                return 0;

            return mConfigTables.TryGetValue(key, out var dict) ? dict.Count : 0;
        }
        
        /// <summary>
        /// 检查配置表是否存在
        /// </summary>
        /// <param name="key">配置表标识符</param>
        /// <returns>是否存在</returns>
        public static bool ContainsConfigTable(string key)
        {
            if (string.IsNullOrEmpty(key))
                return false;

            return mConfigTables.ContainsKey(key);
        }
        
        /// <summary>
        /// 获取所有配置表的键
        /// </summary>
        /// <returns>配置表键列表</returns>
        public static List<string> GetAllConfigTableKeys()
        {
            return mConfigTables.Keys.ToList();
        }
        
        /// <summary>
        /// 尝试获取单行配置数据
        /// </summary>
        /// <param name="key">配置表标识符</param>
        /// <param name="id">配置项ID</param>
        /// <param name="config">输出配置项数据</param>
        /// <param name="isCopy">是否返回副本（true为返回副本，false为返回源数据）</param>
        /// <returns>是否成功获取</returns>
        public static bool TryGetSingleRowConfig(string key, int id, out ConfigTableBase config, bool isCopy = false)
        {
            config = GetSingleRowConfig(key, id, isCopy);
            return config != null;
        }
        
        /// <summary>
        /// 尝试获取单行配置数据（泛型版本）
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="id">配置项ID</param>
        /// <param name="config">输出配置项数据</param>
        /// <param name="isCopy">是否返回副本（true为返回副本，false为返回源数据）</param>
        /// <returns>是否成功获取</returns>
        public static bool TryGetSingleRowConfig<T>(string key, int id, out T config, bool isCopy = false) where T : ConfigTableBase
        {
            config = GetSingleRowConfig<T>(key, id, isCopy);
            return config != null;
        }

        /// <summary>
        /// 异步注册配置表（泛型版本）
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="textAsset">包含JSON数据的TextAsset</param>
        /// <returns>是否注册成功</returns>
        public static async Task<bool> RegisterConfigTableAsync<T>(string key, TextAsset textAsset) where T : ConfigTableBase
        {
            return await Task.Run(() =>
            {
                try
                {
                    RegisterConfigTable<T>(key, textAsset);
                    return true;
                }
                catch (Exception ex)
                {
                    Debug.LogError($"异步注册配置表失败: {ex.Message}");
                    return false;
                }
            });
        }

        /// <summary>
        /// 根据条件查询配置项
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="predicate">查询条件</param>
        /// <returns>满足条件的配置项列表</returns>
        public static List<T> QueryConfigs<T>(string key, Func<T, bool> predicate) where T : ConfigTableBase
        {
            if (string.IsNullOrEmpty(key) || predicate == null)
                return new List<T>();

            var dict = GetConfigTableDic<T>(key, false); // 获取原始数据以提高性能
            if (dict == null)
                return new List<T>();

            return dict.Values.Where(predicate).ToList();
        }

        /// <summary>
        /// 获取满足条件的配置项数量
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="predicate">查询条件</param>
        /// <returns>满足条件的配置项数量</returns>
        public static int CountConfigs<T>(string key, Func<T, bool> predicate) where T : ConfigTableBase
        {
            if (string.IsNullOrEmpty(key) || predicate == null)
                return 0;

            var dict = GetConfigTableDic<T>(key, false); // 获取原始数据以提高性能
            if (dict == null)
                return 0;

            return dict.Values.Count(predicate);
        }

        /// <summary>
        /// 重新加载配置表
        /// </summary>
        /// <typeparam name="T">配置表类型</typeparam>
        /// <param name="key">配置表标识符</param>
        /// <param name="newTextAsset">新的TextAsset</param>
        /// <returns>是否重新加载成功</returns>
        public static bool ReloadConfigTable<T>(string key, TextAsset newTextAsset) where T : ConfigTableBase
        {
            // 先注销旧的配置表
            UnRegisterConfigTable(key);
            
            // 重新注册新的配置表
            try
            {
                RegisterConfigTable<T>(key, newTextAsset);
                return true;
            }
            catch (Exception ex)
            {
                Debug.LogError($"重新加载配置表失败 key {key} Type {typeof(T).Name} Exception: {ex.Message}");
                return false;
            }
        }
    }
}